# -*- coding:utf-8 -*-
"""
@Author : 审心
@Time : 2023/4/28 14:55
获取市场排行商品任务
"""
import math
import shutil
import uuid
from dataclasses import dataclass, field
from typing import Optional, List, Tuple, Union, Dict

from DrissionPage import WebPage
from xlwings import Sheet

from autoTask.taobao.sycm.goods.findMarketRank.FilterAction import FilterAction, FilterActionV2
from autoTask.taobao.sycm.goods.findMarketRank.GetDataAction import GetDataAction
from autoTask.taobao.sycm.utils.close_Ad import tb_slider, close_ad
from autoTask.taobao.util import GoodsUtil
from common.utils import DictUtil, FileUtil, ExcelUtil
from common.utils.ThreadUtil import before_enable_stop_abel_thread
from common.utils.web_page_util import MockTap
from common.logger.log import log_
import xlwings as xw
import pandas as pd

from request.utils.request import Request


@dataclass
class FindMarketRank:
    """
   查找市场排名操作

    Attributes:
      param (dict): 任务参数字典
      page (WebPage): 网页对象，用于获取网页数据。
      action List[Tuple[GetDataAction, FilterAction]]: 获取数据动作对象，过滤数据动作对象。
      result_excel_path (str): 结果表格路径(相对于项目目录)
      excel_action_visible (bool): 表格操作是否显示
    """
    page: WebPage
    param: Optional[dict] = None
    action_list: List[Tuple[GetDataAction, FilterAction]] = field(default_factory=list)
    result_excel_path: str = r"/taskTemplateExcel/goods/findMarketRank/市场排行-商品.xlsx"
    excel_action_visible: bool = False

    def __post_init__(self):
        if self.param is not None:
            search_obj_list = self.param.get("searchObjList")
            for item in search_obj_list:
                self.action_list.append((
                    GetDataAction(category=item.get("category"), date_cycle=item.get("dateCycle")),
                    FilterAction(price_scope=item.get("priceScope"), title_contain_str=item.get("titleContainStr"),
                                 title_not_contain_str=item.get("titleNotContainStr"))
                ))
            self.result_excel_path = FileUtil.get_project_root() + self.result_excel_path

    def __call__(self) -> Union[tuple[str, str]]:
        # 创建工作薄
        book = xw.App(visible=self.excel_action_visible).books.add()
        for action in self.action_list:
            # 获取数据操作对象
            get_data_action = action[0]
            # 过滤操作对象
            filter_action = action[1]
            # 根据品类添加sheet页
            sheet = book.sheets.add(name=get_data_action.category)
            # 过滤列表至结果表格
            result_list = filter_action(get_data_action(self.page))
            # 追加结果列表至
            FindMarketRank.append_result_list_to_sheet(sheet, result_list)
            self.append_goods_img(sheet)
            # 自动设置列宽
            sheet.range('A1').expand('table').columns.autofit()
        if book.sheets.count > 1:
            book.sheets['Sheet1'].delete()
            book.save(self.result_excel_path)
            book.close()
        else:
            raise RuntimeError(f"没有获取到任何数据 : {self}")
        return self.result_excel_path, ".xlsx"

    def append_goods_img(self, sheet: Sheet):
        log_.info("开始追加商品图像")
        img_dir = FileUtil.get_project_root() + r"/DownloadData/sycm_table/goods/img"
        try:
            # E列前新增一列
            sheet.api.Columns(sheet.range('E1').column).Insert()
            # 调整单元格大小
            sheet.range('E1').api.EntireColumn.RowHeight = 40
            sheet.range('E1').api.EntireColumn.ColumnWidth = 6
            # 追加标题
            sheet.range("E1").value = "商品图像"
            # 获取链接列
            print(sheet.range(f"F2:F{ExcelUtil.xw_get_has_content_row(sheet, 'F')}").value)
            links_rows = sheet.range(f"F2:F{ExcelUtil.xw_get_has_content_row(sheet, 'F')}").rows
            for row in links_rows:
                file_name = str(uuid.uuid4()) + ".jpg"
                path = GoodsUtil.dw_master_img(self.page, row[0].value, img_dir, file_name)
                ExcelUtil.xw_append_img_to_cell(sheet, f'E{row.row}', img_path=path)
        finally:
            # 清空图片文件
            FileUtil.clear_folder(img_dir)

    @staticmethod
    def append_result_list_to_sheet(sheet: Sheet, result_list: List):
        # 追加标题
        result_list.insert(0, ["日期", "商品信息", "", "类目", "平台", "商品链接", "宝贝ID", "所属店铺",
                               "店铺id", "交易金额", "交易增长幅度", "访客人数", "搜索人数", "收藏人数",
                               "加购人数", "支付转化率", "支付人数", "客单价", "UV价值", "搜索占比", "收藏率", "加购率",
                               ""])
        # 填充数据
        sheet.range("A1").value = result_list
        # 删除无用的C列
        sheet.range('C:C').api.Delete()
        # 将商品链接列转为链接
        for cell in sheet.range('E2').expand("down"):
            cell.api.Hyperlinks.Add(Anchor=cell.api, Address=cell.value)


@dataclass
class FindMarketRankV2:
    """
   查找市场排名操作

    Attributes:
      page (WebPage): 网页对象，用于获取网页数据。
      action List[Tuple[GetDataAction, FilterActionV2]]: 获取数据动作对象，过滤数据动作对象。
      zip_temp_path : 压缩包临时文件路径
      excel_action_visible (bool): 表格操作是否显示
    """
    page: WebPage
    action_list: List[Tuple[GetDataAction, FilterActionV2]] = field(default_factory=list)
    zip_temp_path: str = FileUtil.get_project_root() + r"/taskTemplateExcel/goods/findMarketRank/zipTemp"
    excel_action_visible: bool = False

    def __post_init__(self):
        # 清除
        FileUtil.clear_folder(self.zip_temp_path)

    @before_enable_stop_abel_thread(target_func=close_ad, is_loop=True)
    def __call__(self) -> Optional[str]:
        for action in self.action_list:
            # 下载商品表格
            excel_path = action[0].call_v2(self.page)
            # 过滤商品表格
            action[1](excel_path)
            # 将表格移动到即将压缩的文件夹下并重命名
            root = FileUtil.get_project_root()
            target = root + fr"/taskTemplateExcel/goods/findMarketRank/zipTemp/{action[0].category}.xlsx"
            shutil.move(excel_path, target)
        if FileUtil.count_files(self.zip_temp_path) > 0:
            return FileUtil.zip_folder(self.zip_temp_path, self.zip_temp_path + r"/任务报表.zip")
        else:
            return None

    @staticmethod
    def builder_by_dict(page: WebPage, param: Dict):
        source = param.get("searchObjList")
        if not source:
            raise RuntimeError("初始化流程参数时失败")
        action_list = []
        for item in source:
            g = GetDataAction(category=item.get("category"), date_cycle=item.get("dateCycle"))
            f = FilterActionV2(min_price_1=item.get("minPrice1"), sort_amount_top_r=item.get("sortAmountTopR"),
                               sort_search_people_top_r=item.get("sortSearchPeopleTopR"),
                               sort_min_uv_price=item.get("sortMinUVPrice"), sort_min_price=item.get("sortMinPrice"),
                               title_contain_str=item.get("titleContainStr"),
                               title_not_contain_str=item.get("titleNotContainStr"))
            action_list.append((g, f))
        return FindMarketRankV2(
            page=page,
            action_list=action_list
        )


@dataclass
class FindMarketRankToSystem:
    """
    查找市场排名操作(获取竞品) 提交到后端管理系统
    :parameter page 页面对象
    :parameter category 品类
    :parameter date_cycle 数据周期 7天/30天
    """
    page: WebPage
    category: str
    date_cycle: str

    @before_enable_stop_abel_thread(target_func=close_ad, is_loop=True)
    def __call__(self):
        """
        :return:
        """
        data: List = GetDataAction(category=self.category, date_cycle=self.date_cycle)(self.page)
        if len(data) == 0:
            log_.info(f"当前对象 : {self}")
            raise RuntimeError("未获取到任何一行数据")
        res = Request('post', 'operationAid/competitorProduct/public/commit', req_title='提交竞品数据',
                      json_data={
                          'dataCycle': data[0][0],
                          'category': data[0][3],
                          'exponentialFields': list(map(lambda i: FindMarketRankToSystem.item_to_dict(i), data))
                      }).send()
        if res.get('code') and res.get('code') != 0:
            raise RuntimeError(f"提交数据时失败, 原因 : {res.get('result')}")

    @staticmethod
    def check_param(param: dict):
        err_param_name = []
        if not param.get('account'):
            err_param_name.append("淘系账号")
        if not param.get('password'):
            err_param_name.append("淘系密码")
        if not param.get('dataCycle'):
            err_param_name.append("数据周期")
        if not param.get('category'):
            err_param_name.append("类目")
        if len(err_param_name) > 0:
            return RuntimeError(f"任务参数异常 : {err_param_name} 参数 : {param}")

    @staticmethod
    def item_to_dict(data):
        return {
            # 商品标题
            'productTitle': data[1],
            # 新品文本 比如 : 天猫新品 可能为 nan
            'newText': data[2] if not pd.isna(data[2]) else None,
            # 类目
            'category': data[3].strip(),
            # 平台
            'platform': data[4],
            # 商品链接
            'productLink': data[5],
            # 商品编号
            'productId': data[6],
            # 店铺名称
            'storeName': data[7],
            # 店铺编号
            'storeId': data[8],
            # 交易金额
            'transactionAmount': data[9],
            # 交易增长幅度
            'transactionGrowthRate': data[10].replace("%", ""),
            # 访客人数
            'visitorsNum': data[11],
            # 搜索人数
            'searchNum': data[12],
            # 收藏人数
            'collectNum': data[13],
            # 加购人数
            'backBuyNum': data[14],
            # 支付转化率
            'payTransformRate': data[15].replace("%", ""),
            # 支付人数
            'payNum': data[16],
            # 客单价
            'unitPrice': data[17],
            # UV 价值
            'uvValue': data[18],
            # 搜索占比
            'searchProportion': data[19].replace("%", ""),
            # 收藏率
            "collectRate": data[20].replace("%", ""),
            # 加购率
            "backBuyRate": data[21].replace("%", ""),
        }
